package io.gitee.wl4837.alatool.core.getter;

import cn.hutool.core.text.CharSequenceUtil;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.function.BiConsumer;


/**
 * 只有一个参数的函数对象<br>
 * 接口灵感来自于<a href="http://actframework.org/">ActFramework</a><br>
 * 一个函数接口代表一个一个函数，用于包装一个函数为对象<br>
 * 在JDK8之前，Java的函数并不能作为参数传递，也不能作为返回值存在，此接口用于将一个函数包装成为一个对象，从而传递对象
 *
 * @author Kingood
 *
 */
@FunctionalInterface
public interface MethodBaseFieldSetter<T, U> extends MethodBaseInfo, Serializable {

    /**
     * Performs this operation on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);

    /**
     * Returns a composed {@code BiConsumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code BiConsumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
        Objects.requireNonNull(after);

        return (l, r) -> {
            accept(l, r);
            after.accept(l, r);
        };
    }

    default String getFieldName() {
        String methodName = getMethodName();
        if (methodName.startsWith("set")) {
            methodName = methodName.substring(3);
        } else {
            throw new RuntimeException();
        }
        return CharSequenceUtil.lowerFirst(methodName);
    }

    default Class<?> getFieldClass() {
        return getField().getClass();
    }

    default Field getField() {
        try {
            return getObjectClass().getField(getFieldName());
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

}